package net.orange.architecture.process;

import java.util.HashMap;
import java.util.Map;

import javax.faces.context.FacesContext;

import net.orange.architecture.db.IObjectManager;
import net.orange.architecture.system.SystemParameters;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.jsf.FacesContextUtils;

/**
 * Process Factory. it can get a relate process object according the special
 * value object. Usually it has three way:<br>
 * <br>
 * 1 - load(Class) : with Aop function(such as security check and auditor)
 * through the web application content.<br>
 * <br>
 * 2 - get(Class) : without the AOP function.<br>
 * <br>
 * 3 - find(Class):with AOP through XML bean factory, it usually in the system
 * internal operation. like the schedule job.
 */
public class ProcessFactory {

	private static WebApplicationContext webContext = null;

	private static BeanFactory appContext = null;

	private static Map<String, IBaseProcess> processMap = new HashMap<String, IBaseProcess>();

	/**
	 * Get the process according the value object class with Aop function(such
	 * as security check and auditor) through the web application content.
	 * 
	 * @param clazz
	 *            The value object class.
	 * @return The relate process object.
	 * @throws Exception
	 */
	public static IBaseProcess load(Class clazz) throws Exception {
		if (webContext == null)
			webContext = FacesContextUtils
					.getWebApplicationContext(FacesContext.getCurrentInstance());
		return (IBaseProcess) webContext.getBean(getProcessName(clazz));

	}

	/**
	 * Get the process according the value object class without the AOP
	 * function.
	 * 
	 * @param clazz
	 *            The value object class.
	 * @return The relate process object.
	 * @throws Exception
	 */
	public static IBaseProcess get(Class clazz) throws Exception {
		IBaseProcess process = processMap.get(clazz.getName());
		if (process == null) {
			process = (IBaseProcess) getProcessClazz(clazz).newInstance();

			if (webContext == null)
				webContext = FacesContextUtils
						.getWebApplicationContext(FacesContext
								.getCurrentInstance());

			process.setDao((IObjectManager) webContext.getBean(getDaoName(clazz)));

			processMap.put(clazz.getName(), process);
		}
		return process;
	}

	/**
	 * Get the process according the value object class with AOP through XML
	 * bean factory, it usually in the system internal operation. like the
	 * schedule job.
	 * 
	 * @param clazz
	 *            The value object class.
	 * @return The relate process object.
	 * @throws Exception
	 */
	public static IBaseProcess find(Class clazz) throws Exception {
		if (appContext == null) {
			appContext = (BeanFactory) new ClassPathXmlApplicationContext(
					SystemParameters.ARCH_APPCONTEXT_FILES);
		}
		return (IBaseProcess) appContext.getBean(getProcessName(clazz));
	};

	/**
	 * Get the process class name string according the value object class.
	 * 
	 * @param clazz
	 *            The value object class.
	 * @return The process class name.
	 */
	public static String getProcessName(Class clazz) {
		String objectClazzName = clazz.getName();
		return objectClazzName.substring(objectClazzName.lastIndexOf(".") + 1,
				objectClazzName.lastIndexOf(".") + 2).toLowerCase()
				+ objectClazzName.substring(
						objectClazzName.lastIndexOf(".") + 2, objectClazzName
								.length()) + "Process";

	}

	/**
	 * Get the process DAO class name string according the value object class.
	 * 
	 * @param clazz
	 *            The value object class.
	 * @return The process DAO class name.
	 * @throws Exception
	 */
	public static String getDaoName(Class objectClazz) {
		String objectClazzName = objectClazz.getName();
		String objectShortName = objectClazzName.substring(objectClazzName
				.lastIndexOf(".") + 1, objectClazzName.length());
		return objectShortName.substring(0, 1).toLowerCase()
				+ objectShortName.substring(1, objectShortName.length())
				+ "Dao";
	}

	/**
	 * Get the process class according the value object class.
	 * 
	 * @param clazz
	 *            The value object class.
	 * @return The process class.
	 * @throws Exception
	 */
	public static Class getProcessClazz(Class clazz) throws Exception {
		String objectClazzName = clazz.getName();
		String valueObjectName = objectClazzName.substring(objectClazzName
				.lastIndexOf(".") + 1, objectClazzName.length());

		String processClazzName = objectClazzName.substring(0,
				objectClazzName.lastIndexOf(".")).substring(
				0,
				objectClazzName.substring(0, objectClazzName.lastIndexOf("."))
						.lastIndexOf("."))
				+ ".logic." + valueObjectName + "Process";
		return Class.forName(processClazzName);
	}
}
